-- UISystemSetting
-- Create by zouyb Jan/25/2015
-- 系统设置界面

require "game/ui/form/setting/UIErrorInfo";
require "game/ui/form/setting/UIGD";
require "game/ui/debug/UIClientStatus";
require "game/ui/form/setting/UIAccountBind";

UISystemSetting = class("UISystemSetting",function()
    return cc.Layer:create()
end)

function UISystemSetting.create(showType)
    return UISystemSetting.new(showType);
end

-- 内部函数声明
local resize;
local sortTitles;

-- 使用本界面的项目
local SYSTEM   = 1;   -- 系统设置
local NOTIFY   = 2;   -- 公告
local ACCOUNT  = 3;   -- 账号
local LANGUAGE = 4;   -- 语言
local SOUND    = 5;   -- 声音
local PUSH     = 6;   -- 推送
local ABOUT    = 7;   -- 关于
local FUNC     = 8;   -- 功能
local DEBUG    = 10;  -- DEBUG
local TAB_NUM  = 3;   -- 标签页数量

-- 标签页界面
local firstType = {SYSTEM, NOTIFY, DEBUG};
-- 系统设置内容
local systemSettingType = {};
-- 相关对应
local systemTypeFlag = { ["language"] = LANGUAGE, ["sound"] = SOUND, ["push"] = PUSH, ["about"] = ABOUT, ["func"] = FUNC, };

-- 语言设置内容
local languageSettingType = {};

-- 声音设置内容
local soundSettingType = { "music", "sound"};
-- 推送设置内容（PushM里获取）
local pushSettingType = {};

-- 功能设置内容
local funcSettingType = {};

-- DEBUG标签页选项
local systemDebugType = { "gd", "error", "clear"};
-- 海外版本才出现
local overseaShow = {
    "email", "feedBack", "facebook", "sdk_achievement", "sdk_leaderboard", "forum",
};

-- 构造函数
function UISystemSetting:ctor(showType)
    self:setName("UISystemSetting");

    -- 初始化
    local node = cc.CSLoader:createNode("layout/setting/SystemSetting.csb");
    self:addChild(node);
    self.node = node;

    self:setLocalZOrder(UIMgr.BONUS_NOTIFY_ZORDER + 1);

    -- 语言设置项相关配置
    self:initAboutLang()

    -- 整理当前可以显示的设置项目
    self:arrangeSystemItems();

    if showType then
        -- 指定打开界面
        self.type = showType;
    else
        -- 默认系统设置界面
        self.type = SYSTEM;
    end

    -- 推送类型
    pushSettingType = PushM.getPushTypeElse();

    local scrollview = findChildByName(self.node, "CT/system_setting");
    self.scrollview = scrollview;

    -- 容器原本的内高
    self.oriHeight = scrollview:getInnerContainerSize().height

    -- 重绘
    self:redraw();

    -- 标签页
    self:redrawTabs();

    -- 注册点击事件
    self:registerTouchEvent();

    -- 注册事件处理回调函数
    self:registerEventCallback();

    -- 适配
    resize(node);
end

-- 整理当前可以显示的设置项目
function UISystemSetting:arrangeSystemItems()
    -- 根据玩家语言得到显示的系统项
    systemSettingType = table.deepcopy(FormulaM.invoke("CALC_SYSTEM_SETTING_TYPE"));

    -- TODO把隐藏项目也搬到公式中去
    -- 目前先写在这里方便查看

    -- 配置不允许切语言/非中文版本允许切换
    if ALLOW_TO_SWITCH_LANG ~= 1 and getLang() == "zh" then
        for index, typeName in pairs(systemSettingType) do
            if typeName == "language" then
                table.remove(systemSettingType, index);
                break;
            end
        end
    end

    -- IOS屏蔽成就、分享、排行榜、faceBook入口
    if ServerStatusM.query(MODULE_SWITCH_IOS_BLOCK_CONTENT) == 1 then
        for index = #systemSettingType, 1, -1 do
            if systemSettingType[index] == "facebook" or
                systemSettingType[index] == "share" or
                systemSettingType[index] == "sdk_achievement" or
                systemSettingType[index] == "sdk_leaderboard" then
                table.remove(systemSettingType, index);
            end
        end
    end

    -- 海外的IOS屏蔽密令
    if ServerStatusM.query(MODULE_SWITCH_IOS_OVERSEA_CLOSE) == 1 then
        for index = #systemSettingType, 1, -1 do
            if systemSettingType[index] == "card_bonus" then
                table.remove(systemSettingType, index);
                break;
            end
        end
    end

    -- 屏蔽评分和论坛
    if ServerStatusM.query(MODULE_SWITCH_BLOCK_GRADE_AND_FORUM) == 1 then
        for index = #systemSettingType, 1, -1 do
            if systemSettingType[index] == "forum" or
                systemSettingType[index] == "feedBack" then
                table.remove(systemSettingType, index);
            end
        end
    end

    -- UC版本关闭帮助按钮
    if PUBLISH_PLATFORM == PUBLISH_TYPE_UC then
        table.removeItem(systemSettingType, "help");
    end

    -- 分享功能未开放时，隐藏入口
    if not isShareFuncOpen() then
        table.removeItem(systemSettingType, "share");
    end

    -- 仅对海外版本开放的项目
    if not isOverseaPackage() then
        local finalSystemType = {};
        for index, typeName in pairs(systemSettingType) do

            if table.indexOf(overseaShow, typeName) == -1 then
                table.insert(finalSystemType, typeName);
            elseif (typeName == "sdk_achievement" or typeName == "sdk_leaderboard") and
                PUBLISH_PLATFORM == PUBLISH_TYPE_APP_STORE_CN then
                -- 国内ios需要开放成就和排行榜
                table.insert(finalSystemType, typeName);
            end
        end
        -- 更新系统项
        systemSettingType = finalSystemType;
    end

    -- 显示error按钮
    if SHOW_ERROR == 1 then
        table.insert(systemSettingType, "error");
    end

    -- 显示"关于"按钮
    if SHOW_ABOUT == 1 then
        table.insert(systemSettingType, "about");
    end

    -- 个人中心
    if not isAccountCenterOpen() then
        table.removeItem(systemSettingType, "account_center");
    end

    -- 手机号记录
    if not PhoneNumberRecordM.canShowPhoneRecord() then
        table.removeItem(systemSettingType, "phone_record");
    end

    -- 身份证记录
    if not PhoneNumberRecordM.canShowIdCardRecord() then
        print("should remove id_card");
        table.removeItem(systemSettingType, "id_card_record");
    end

    -- 雷霆运营(需要通关4-1)
    if PUBLISH_PLATFORM ~= PUBLISH_TYPE_LT
        or not DungeonAreaM.isDungeonPassed(ME.user, 41) then
        table.removeItem(systemSettingType, "lt_operation");
    end

    -- 雷霆版本需要开放论坛入口
    if PUBLISH_PLATFORM == PUBLISH_TYPE_LT then
        -- 未开启或第一小关未通关都不开启
        if ServerStatusM.query(MODULE_SWITCH_BLOCK_LEITING_FORUM) == 1
            or not DungeonAreaM.isDungeonPassed(ME.user, 11) then
            table.removeItem(systemSettingType, "forum");
        else
            table.insert(systemSettingType, "forum");
        end
    end

    if ServerStatusM.query(MODULE_SWITCH_BLOCK_SHARE) == 1 then
        -- 服务器屏蔽了分享功能
        table.removeItem(systemSettingType, "share");
    end
end

-- 获取语言设置项相关
function UISystemSetting:initAboutLang()
    languageSettingType = LanguageM.getLanguageSettingType();
end

-- 绘制时间
function UISystemSetting:redrawTime()
    -- 时间标题
    local title2Label = findChildByName(self.node, "CT/title2");

    local function tick()
        if self.type == SYSTEM then
            local serverTime = TimeM.getServerTime() - TimeM.getTimeOffsetDifference();
            local t = os.date("*t", serverTime);

            -- 拼接服务器时间
            local timeText = string.format(getLocStr("world_time"), t.month, t.day, t.hour, t.min);
            title2Label:setString(timeText);
            performWithDelay(self.node, tick, 1);
        end
    end

    tick();
end

-- 重绘
function UISystemSetting:redraw()
    -- 标题
    local title1Label = findChildByName(self.node, "CT/title1");
    local title2Label = findChildByName(self.node, "CT/title2");

    -- 系统设置
    local systemNode = findChildByName(self.node, "CT/system_setting");
    systemNode:setVisible(false);

    -- 公告条目
    local notifyNode = findChildByName(self.node, "CT/notify_lines");
    notifyNode:setVisible(false);

    -- TAB节点
    local tabNode = findChildByName(self.node, "CT/tabs");
    tabNode:setVisible(false);

    -- 隐藏滚动条
    if self.indicator then
        self.indicator:setVisible(false);
    end

    -- 隐藏模板标题
    local title = findChildByName(self.node, "CT/template/title");
    local subhead = findChildByName(self.node, "CT/template/subhead");
    subhead:setVisible(false);
    title:setVisible(false);

    -- 确定按钮
    local btnOk = findChildByName(self.node, "BT/btn_ok");
    btnOk:setVisible(false);
    btnOk:setTouchEnabled(true);
    btnOk:setBright(true);

    if self.type == SYSTEM then
        -- 系统设置
        title1Label:setString(getLocStr("system_setting"));
        tabNode:setVisible(true);
        -- 时间设置
        self:redrawTime();
        -- 绘制格子
        self:redrawItem();
    elseif self.type == NOTIFY then
        -- 公告
        title1Label:setString(getLocStr("game_notify"));
        title2Label:setString(getLocStr("the_last_twenty"));
        tabNode:setVisible(true);
        -- 公告绘制
        self:redrawLines();
    elseif self.type == LANGUAGE then
        -- 语言选择
        title1Label:setString(getLocStr("choose_language"));
        -- 当前语言
        local currentLanguage = "english";
        for _, language in pairs(languageSettingType) do
            if language == getLang() then
                currentLanguage = language;
                break;
            end
        end
        title2Label:setString(getLocStr("language_" .. currentLanguage));
        btnOk:setVisible(true);
        self:redrawItem();
    elseif self.type == SOUND then
        -- 声音设置
        title1Label:setString(getLocStr("sound_setting"));
        title2Label:setString(getLocStr("sound_setting_explain"));
        self:redrawLines();
    elseif self.type == ABOUT then
        -- 关于
        self:redrawLines();
    elseif self.type == PUSH then
        -- 推送设置
        title1Label:setString(getLocStr("push_setting"));
        title2Label:setString(getLocStr("push_setting_explain"));
        self:redrawLines();
    elseif self.type == FUNC then
        -- 推送设置
        title1Label:setString(getLocStr("func_setting"));
        title2Label:setString(getLocStr("func_setting_explain"));
        self:redrawLines();
    elseif self.type == DEBUG then
        -- DEBUG模式的选项
        title1Label:setString(getLocStr("btn_text_debug"));
        title2Label:setString(getLocStr("btn_text_debug"));
        tabNode:setVisible(true);
        btnOk:setVisible(false);
        -- 绘制格子
        self:redrawItem();
    end
    TextStyleM.setTitleStyle(title1Label);
    TextStyleM.setSubheadStyle(title2Label);

    -- 滑动到最顶端
    scrollToTop(systemNode);
    scrollToTop(notifyNode);
end

-- 绘制格子
function UISystemSetting:redrawItem()
    local systemNode = findChildByName(self.node, "CT/system_setting");

    -- 去除所有子节点
    systemNode:removeAllChildren();

    if self.type == SYSTEM then
        -- 系统设置
        self:initSystemItem();
    elseif self.type == LANGUAGE then
        -- 语言设置
        self:initLanguageItem();
    elseif self.type == DEBUG then
        -- DEBUG
        self:initDebugItem();
    else
        -- 不是可以处理的类型
        return;
    end

    systemNode:setVisible(true);
end

-- 设置格子位置
function UISystemSetting:setItemPosition(child, i, textNode, totalHeight)
    local x = (i - 1) % 4 * 125 + 52;
    local y = math.floor((i - 1) / 4) * -160 + totalHeight - 60;
    child:setAnchorPoint(cc.p(0.5, 0.5));
    child:setScale(0.85);
    child:setPosition(cc.p(x, y));
    child:setVisible(true);

    textNode:setAnchorPoint(cc.p(0.5, 0.5));
    textNode:setPosition(cc.p(x, y - 75));
end

-- DEBUG格子
function UISystemSetting:initDebugItem()
    local itemNode = cc.CSLoader:createNode("layout/workshop/StoreItem.csb");
    local systemNode = findChildByName(self.node, "CT/system_setting");
    local widgetItem = replaceNodeWithWidget(itemNode);

    -- 计算容器高度
    local needHeight = math.ceil(#systemDebugType / 4) * 160 + 10;
    local totalHeight = math.max(self.oriHeight, needHeight);
    systemNode:setInnerContainerSize(cc.size(systemNode:getInnerContainerSize().width, totalHeight));

    for i = 1, #systemDebugType do
        local child = widgetItem:clone();
        local textNode = ccui.Text:create();
        self:setItemPosition(child, i, textNode, totalHeight);
        child.index = systemDebugType[i];

        local icon = child:getChildByName("icon");
        local iconPath;
        iconPath = getSettingIconPath("system", "default");
        icon:loadTexture(iconPath);

        local focus = child:getChildByName("focus");
        focus:setVisible(false);

        -- 注册点击事件
        self:registerItemTouchEvent(child);
        TextStyleM.setTextStyle(textNode, TextStyleM.TEXT_SIZE_MINI, TextStyleM.TEXT_COLOR_DARK_BROWN);
        textNode:setString(getLocStr("debug_" .. systemDebugType[i]));

        systemNode:addChild(child);
        systemNode:addChild(textNode);
    end
end

-- 语言设置格子
function UISystemSetting:initLanguageItem()
    local btnOk = findChildByName(self.node, "BT/btn_ok");
    local itemNode = cc.CSLoader:createNode("layout/workshop/StoreItem.csb");
    local systemNode = findChildByName(self.node, "CT/system_setting");
    local widgetItem = replaceNodeWithWidget(itemNode);

    -- 计算容器高度
    local needHeight = math.ceil(#languageSettingType / 4) * 160 + 10;
    local totalHeight = math.max(self.oriHeight, needHeight);
    systemNode:setInnerContainerSize(cc.size(systemNode:getInnerContainerSize().width, totalHeight));

    for i = 1, #languageSettingType do
        local child = widgetItem:clone();
        local textNode = ccui.Text:create();
        self:setItemPosition(child, i, textNode, totalHeight);
        child.index = languageSettingType[i];

        local icon = child:getChildByName("icon");
        local iconPath;

        iconPath = getSettingIconPath("language", languageSettingType[i]);
        icon:loadTexture(iconPath);

        local focus = child:getChildByName("focus");

        local textColorType = TextStyleM.TEXT_COLOR_GRAY;

        -- 默认选中当前语言
        if child.index == getLang() then
            focus:setVisible(true);
            self.focus = child;

            -- 选择语言为当前语言，确认按钮需要置灰
            if child.index == getLang() then
                btnOk:setTouchEnabled(false);
                btnOk:setBright(false);
            else
                btnOk:setTouchEnabled(true);
                btnOk:setBright(true);
            end
        else
            focus:setVisible(false);
        end

        -- 当前选择的语言字体颜色不同
        if child.index == getLang() then
            textColorType = TextStyleM.TEXT_COLOR_BLUE;
        end

        -- 注册点击事件
        self:registerItemTouchEvent(child);
        textNode:setString(getLocStr(string.format("language_%s", languageSettingType[i])));
        textNode:setTextColor(textColorType);

        -- 适应系统字变细，统一扩大再缩小
        textNode:setFontSize(TextStyleM.TEXT_SIZE_MINI + 4);
        textNode:setScale(0.85);

        systemNode:addChild(child);
        systemNode:addChild(textNode);
    end
end

-- 系统设置格子
function UISystemSetting:initSystemItem()
    local itemNode = cc.CSLoader:createNode("layout/workshop/StoreItem.csb");
    local systemNode = findChildByName(self.node, "CT/system_setting");
    local widgetItem = replaceNodeWithWidget(itemNode);

    -- 计算容器高度
    local needHeight = math.ceil(#systemSettingType / 4) * 160 + 10;
    local totalHeight = math.max(self.oriHeight, needHeight);
    systemNode:setInnerContainerSize(cc.size(systemNode:getInnerContainerSize().width, totalHeight));

    for i = 1, #systemSettingType do
        local child = widgetItem:clone();
        local textNode = ccui.Text:create();
        self:setItemPosition(child, i, textNode, totalHeight);
        child.index = systemSettingType[i];

        local icon = child:getChildByName("icon");
        local iconPath;
        if child.index == "language" then
            -- 语言图标
            iconPath = getSettingIconPath("language", getLang());
        elseif child.index == "account" then
            -- 账号图标
            local iconName;
            if PUBLISH_PLATFORM == PUBLISH_TYPE_GOOGLE_PLAY then
                iconName = "account_google";
            elseif PUBLISH_PLATFORM == PUBLISH_TYPE_APP_STORE or PUBLISH_PLATFORM == PUBLISH_TYPE_APP_STORE_CN then
                iconName = "account_gamecenter";
            elseif PUBLISH_PLATFORM == PUBLISH_TYPE_UC then
                iconName = "account_uc";
            elseif PUBLISH_PLATFORM == PUBLISH_TYPE_AMAZON then
                iconName = "account_amazon";
            else
                iconName = "account";
            end
            iconPath = getSettingIconPath("system", iconName);
        else
            if systemSettingType[i] == "id_card_record" then
                iconPath = getSettingIconPath("system", "phone_record");
            else
                iconPath = getSettingIconPath("system", systemSettingType[i]);
            end
        end
        icon:loadTexture(iconPath);

        -- 注册点击事件
        self:registerItemTouchEvent(child);

        TextStyleM.setTextStyle(textNode, TextStyleM.TEXT_SIZE_MINI, TextStyleM.TEXT_COLOR_DARK_BROWN);
        if child.index == "error" then
            -- 错误日志
            textNode:setString(getLocStr("debug_error"));
        else
            textNode:setString(getLocStr("system_" .. systemSettingType[i]));
        end

        systemNode:addChild(child);
        systemNode:addChild(textNode);

        self:checkTip(child);
    end
end

-- 检查是否需要提示
function UISystemSetting:checkTip(child)
    local tip = findChildByName(child, "tip");
    tip:setVisible(false);
    if child.index == "lt_operation" then
        local hasClick = UserDefaultM.getStringForKey("click_lt_operation");
        if tonumber(hasClick) ~= 1 then
            playBubbleAnima(tip, false, 0.8);
        end
    elseif child.index == "phone_record" then
        playBubbleAnima(tip, false, 0.8);
    end
end

-- 绘制横条项目
function UISystemSetting:redrawLines()
    local notifyNode = findChildByName(self.node, "CT/notify_lines");

    -- 去除所有增加节点
    notifyNode:removeAllChildren();

    if self.type == NOTIFY then
        -- 公告
        self:redrawNotifyLines();
    elseif self.type == SOUND then
        -- 声音设置
        self:redrawSoundLines();
    elseif self.type == PUSH then
        -- 推送设置
        self:redrawPushLines();
    elseif self.type == FUNC then
        -- 功能设置
        self:redrawFuncLines();
    elseif self.type == ABOUT then
        -- 关于
        self:redrawAboutLines();
    else
        -- 不是可以绘制的类型
        return;
    end

    notifyNode:setVisible(true);
end

-- 绘制Top横线
-- 为了防止滚动穿帮，先这么处理
function UISystemSetting:redrawTopLines(addNode, totalHeight)
    local lineNode = cc.CSLoader:createNode("layout/setting/NotifyNode.csb");
    local widget = replaceNodeWithWidget(lineNode);

    local child = widget:clone();
    local icon = child:getChildByName("icon");
    local text =  child:getChildByName("text");
    local bubble = child:getChildByName("bubble");
    local y = totalHeight - 20;
    child:setAnchorPoint(cc.p(0.5, 0.5));
    child:setPositionX(20);
    child:setPositionY(y);
    icon:setVisible(false);
    text:setVisible(false);
    bubble:setVisible(false);

    addNode:addChild(child);
end

-- 设置项目位置
function UISystemSetting:setLineItemPosition(child, i, totalHeight)
    local y = (i - 1) * -60 + totalHeight - 80;
    child:setAnchorPoint(cc.p(0.5, 0.5));
    child:setPositionX(20);
    child:setPositionY(y);
    child:setVisible(true);
end

-- 绘制公告条目
function UISystemSetting:redrawNotifyLines()
    local addNode = findChildByName(self.node, "CT/notify_lines");
    local lineNode = cc.CSLoader:createNode("layout/setting/NotifyNode.csb");
    local widget = replaceNodeWithWidget(lineNode);

    -- 获取所有公告标题
    local titles = GameBoardM.getAllTitle();
    -- 获取玩家阅读公告记录
    local readRecord = GameBoardM.getUserReadRecord();

    -- 排序
    table.sort(titles, sortTitles);

    -- 计算容器高度
    local needHeight = GameBoardM.getTitleCount() * 60 + 30;
    local totalHeight = math.max(self.oriHeight, needHeight);
    addNode:setInnerContainerSize(cc.size(addNode:getInnerContainerSize().width, totalHeight));

    -- 绘制顶部横线
    if GameBoardM.getTitleCount() > 0 then
        self:redrawTopLines(addNode, totalHeight);
    end

    if self.indicator then
        -- 隐藏原本的
        self.indicator:setVisible(false);
        self.indicator = nil;
    end

    if totalHeight > self.oriHeight then
        -- 增加新的滚动条
        UIIndicator.attach(addNode);
        self.indicator = addNode:getParent():getChildByName("UIIndicator");
        self.indicator:setVisible(true);
    end

    local i = 1;
    for index, m in pairs(titles) do
        local child = widget:clone();
        local icon = child:getChildByName("icon");
        local text =  child:getChildByName("text");
        local bubble = child:getChildByName("bubble");
        local panel  = child:getChildByName("panel");
        self:setLineItemPosition(child, i, totalHeight);

        -- 根据公告类型获取图标
        local iconPath = getSettingIconPath("board", tostring(m["type"]));
        local bubblePath = getSettingIconPath("system", "read");
        local oriScale = bubble:getScale();
        icon:loadTexture(iconPath);
        bubble:loadTexture(bubblePath);

        -- 设置标题
        text:setString(m["title"]);

        local color = TextStyleM.TEXT_COLOR_DARK_BROWN;
        if table.indexOf(readRecord, m["id"]) == -1 then
            -- 没有读过
            color = TextStyleM.TEXT_COLOR_GREEN;
        end
        TextStyleM.setTextStyle(text, TextStyleM.TEXT_SIZE_SMALL2, color);

        local function openGameBoard()
            AudioM.playFx("button_click");

            -- 打开公告界面
            showGameBoard(m["id"]);
        end

        local function onClick(sender, eventType)
            -- 点击时的回调
            if eventType == ccui.TouchEventType.began then
                bubble:setScale(oriScale - 0.1);
            elseif eventType == ccui.TouchEventType.canceled then
                bubble:setScale(oriScale);
            elseif eventType == ccui.TouchEventType.ended then
                bubble:setScale(oriScale);
                openGameBoard();
            end
        end
        bubble:addTouchEventListener(onClick);

        local function onClick2(sender, eventType)
            -- 扩大响应区域，点击时的回调
            if eventType == ccui.TouchEventType.ended then
                openGameBoard();
            end
        end
        panel:addTouchEventListener(onClick2);

        addNode:addChild(child);
        i = i + 1;
    end
end

-- 排序：未阅读/时间高的优先
function sortTitles(item1, item2)
    -- 获取玩家阅读公告记录
    local readRecord = GameBoardM.getUserReadRecord();

    local index1 = table.indexOf(readRecord, item1["id"]);
    local index2 = table.indexOf(readRecord, item2["id"]);

    if (index1 ~= index2) and (index1 == -1 or index2 == -1) then
        return table.indexOf(readRecord, item1["id"]) < table.indexOf(readRecord, item2["id"]);
    end

    -- 按时间排序
    local createTimeA = item1["create_time"] or 1000;
    local createTimeB = item2["create_time"] or 1000;

    return createTimeA > createTimeB;
end

-- 绘制声音设置
function UISystemSetting:redrawSoundLines()
    local addNode = findChildByName(self.node, "CT/notify_lines");
    local lineNode = cc.CSLoader:createNode("layout/setting/NotifyNode.csb");
    local widget = replaceNodeWithWidget(lineNode);

    -- 计算容器高度
    local needHeight = #soundSettingType * 60 + 30;
    local totalHeight = math.max(self.oriHeight, needHeight);
    addNode:setInnerContainerSize(cc.size(addNode:getInnerContainerSize().width, totalHeight));

    -- 绘制顶部横线
    self:redrawTopLines(addNode, totalHeight);

    -- 音乐/音效默认值
    if not UserDefaultM.getStringForKey("fx_volume")
        or UserDefaultM.getStringForKey("fx_volume") == "" then
        self.fxPercent = 100;
    else
        self.fxPercent = tonumber(UserDefaultM.getStringForKey("fx_volume"));
    end

    if not UserDefaultM.getStringForKey("bgm_volume")
        or UserDefaultM.getStringForKey("bgm_volume") == "" then
        self.bgmPercent = 100;
    else
        self.bgmPercent = tonumber(UserDefaultM.getStringForKey("bgm_volume"))
    end

    for i = 1, #soundSettingType do
        local child = widget:clone();
        local icon = child:getChildByName("icon");
        local text =  child:getChildByName("text");
        local bubble = child:getChildByName("bubble");
        self:setLineItemPosition(child, i, totalHeight);

        local iconPath = getSettingIconPath("sound", soundSettingType[i]);
        icon:loadTexture(iconPath);
        text:setString(getLocStr("sound_" .. soundSettingType[i]));

        local function drawBubble()
            -- 字体颜色
            local color = TextStyleM.TEXT_COLOR_DARK_BROWN;

            if soundSettingType[i] == "music" then
                if self.bgmPercent > 0 then
                    bubble:loadTexture(getSettingIconPath("system", "open"));
                else
                    bubble:loadTexture(getSettingIconPath("system", "close"));
                    color = TextStyleM.TEXT_COLOR_DARK_RED;
                end
            else
                if self.fxPercent > 0 then
                    bubble:loadTexture(getSettingIconPath("system", "open"));
                else
                    bubble:loadTexture(getSettingIconPath("system", "close"));
                    color = TextStyleM.TEXT_COLOR_DARK_RED;
                end
            end

            -- 根据选择设置前字颜色
            TextStyleM.setTextStyle(text, TextStyleM.TEXT_SIZE_SMALL2, color);
        end

        local function onClick(sender, eventType)
            -- 点击时的回调
            if eventType == ccui.TouchEventType.ended then
                AudioM.playFx("button_click");
                local msg;
                if soundSettingType[i] == "music" then
                    if self.bgmPercent > 0 then
                        self.bgmPercent = 0;
                        msg = getLocStr("sound_off_tips");
                    else
                        self.bgmPercent = 100;
                        msg = getLocStr("sound_on_tips");
                    end

                    -- 直接设置
                    AudioM.setVolume(self.bgmPercent / 100);
                    UserDefaultM.setStringForKey("bgm_volume", tostring(self.bgmPercent));

                    -- 提示飘字
                    alert(msg);
                else
                    local msg;
                    if self.fxPercent > 0 then
                        self.fxPercent = 0;
                        msg = getLocStr("fx_off_tips");
                    else
                        self.fxPercent = 100;
                        msg = getLocStr("fx_on_tips");
                    end

                    -- 直接设置
                    AudioEngine.setEffectsVolume(self.fxPercent / 100);
                    UserDefaultM.setStringForKey("fx_volume", tostring(self.fxPercent));

                    -- 提示
                    alert(msg);
                end
                drawBubble();
            end
        end
        bubble:addTouchEventListener(onClick);

        drawBubble();

        addNode:addChild(child);
    end
end

-- 绘制关于设置
function UISystemSetting:redrawAboutLines()
    local addNode = findChildByName(self.node, "CT/notify_lines");
    local lineNode = cc.CSLoader:createNode("layout/setting/NotifyNode.csb");
    local widget = replaceNodeWithWidget(lineNode);

    -- 计算容器高度
    local needHeight = #soundSettingType * 60 + 30;
    local totalHeight = math.max(self.oriHeight, needHeight);
    addNode:setInnerContainerSize(cc.size(addNode:getInnerContainerSize().width, totalHeight));

    -- 绘制顶部横线
    self:redrawTopLines(addNode, totalHeight);

    -- 文本列表
    local clientVersion;
    local list = string.explode(CLIENT_VERSION, "-");
    if #list == 1 then
        clientVersion = list[1];
    elseif #list == 2 then
        clientVersion = list[2];
    end

    local textList = {
        string.format(getLocStr("display_version"), clientVersion),
        string.format(getLocStr("real_version"), list[1]),
    };

    for i = 1, 2 do
        local child = widget:clone();
        local text =  child:getChildByName("text");
        local icon = child:getChildByName("icon");
        icon:setVisible(false);
        local bubble = child:getChildByName("bubble");
        bubble:setVisible(false);

        self:setLineItemPosition(child, i, totalHeight);

        TextStyleM.setTextStyle(text, TextStyleM.TEXT_SIZE_SMALL2, TextStyleM.TEXT_COLOR_DARK_BROWN);
        text:setString(textList[i]);

        addNode:addChild(child);
    end
end

-- 绘制推送条目
function UISystemSetting:redrawPushLines()
    local scrollview = findChildByName(self.node, "CT/notify_lines");
    local lineNode = cc.CSLoader:createNode("layout/setting/NotifyNode.csb");

    self.pushSetting = PushM.getPushSetting();
    self.pushSet = {};

    scrollview:jumpToTop();

    -- 图标间距(横向)
    local wGap = 0;

    -- 图标间距(纵向)
    local hGap = 0;

    -- 格子宽度
    local itemWidth = 0;

    -- 格子高度
    local itemHeight = 61;

    -- 左边距
    local leftWGap = 20;

    -- 行间距
    local topGap = 10;
    local bottomHGap = 0;

    -- 单页最大可容纳列数
    local MIN_GRID_COLUMN = 1;

    -- 获取记录总数
    local totalNum = #pushSettingType;

    -- 初始化滚动条
    ScrollTool.initScrollGridsVertical(self, scrollview,
        lineNode, totalNum, MIN_GRID_COLUMN, wGap, hGap, itemWidth,
        itemHeight, topGap, bottomHGap, leftWGap, nil, self.initPushItem);

    -- 绘制顶部横线
    self:redrawTopLines(scrollview, scrollview:getInnerContainerSize().height);
end

-- 绘制推送项目
function UISystemSetting:initPushItem(child, index)
    local icon = child:getChildByName("icon");
    local text =  child:getChildByName("text");
    local bubble = child:getChildByName("bubble");

    local iconName = PushM.queryType(pushSettingType[index], "icon");
    icon:loadTexture(getSettingIconPath("push", iconName));

    if self.pushSetting[pushSettingType[index]] == 1 then
        bubble:loadTexture(getSettingIconPath("system", "open"));
        self.pushSet[pushSettingType[index]] = 1;
        TextStyleM.setTextStyle(text, TextStyleM.TEXT_SIZE_SMALL2, TextStyleM.TEXT_COLOR_DARK_BROWN);
    else
        bubble:loadTexture(getSettingIconPath("system", "close"));
        self.pushSet[pushSettingType[index]] = 0;
        TextStyleM.setTextStyle(text, TextStyleM.TEXT_SIZE_SMALL2, TextStyleM.TEXT_COLOR_DARK_RED);
    end
    self.pushSet["special"] = 1;

    text:setString(PushM.queryType(pushSettingType[index], "title_desc"));

    local function onClick(sender, eventType)
        -- 点击时的回调
        if eventType == ccui.TouchEventType.ended then
            AudioM.playFx("button_click");
            if self.pushSet[pushSettingType[index]] == 1 then
                self.pushSet[pushSettingType[index]] = 0;
                alert(getLocStr("push_off_tips"));
                bubble:loadTexture(getSettingIconPath("system", "close"));
                TextStyleM.setTextStyle(text, TextStyleM.TEXT_SIZE_SMALL2, TextStyleM.TEXT_COLOR_DARK_RED);
            else
                self.pushSet[pushSettingType[index]] = 1;
                alert(getLocStr("push_on_tips"));
                bubble:loadTexture(getSettingIconPath("system", "open"));
                TextStyleM.setTextStyle(text, TextStyleM.TEXT_SIZE_SMALL2, TextStyleM.TEXT_COLOR_DARK_BROWN);
            end
        end
    end
    bubble:addTouchEventListener(onClick);
end

-- 绘制功能设置条目
function UISystemSetting:redrawFuncLines()
    local scrollview = findChildByName(self.node, "CT/notify_lines");
    local lineNode = cc.CSLoader:createNode("layout/setting/NotifyNode.csb");

    self.funcSetting = GameFuncSettingM.getFuncSetting();
    self.funcSet = {};

    scrollview:jumpToTop();

    -- 图标间距(横向)
    local wGap = 0;

    -- 图标间距(纵向)
    local hGap = 0;

    -- 格子宽度
    local itemWidth = 0;

    -- 格子高度
    local itemHeight = 70;

    -- 左边距
    local leftWGap = 20;

    -- 行间距
    local topGap = 10;
    local bottomHGap = 0;

    -- 单页最大可容纳列数
    local MIN_GRID_COLUMN = 1;

    -- 获取记录总数
    local totalNum = #self.funcSetting;

    -- 初始化滚动条
    ScrollTool.initScrollGridsVertical(self, scrollview,
        lineNode, totalNum, MIN_GRID_COLUMN, wGap, hGap, itemWidth,
        itemHeight, topGap, bottomHGap, leftWGap, nil, self.initFuncItem);

    -- 绘制顶部横线
    self:redrawTopLines(scrollview, scrollview:getInnerContainerSize().height);
end

-- 绘制功能设置项目
function UISystemSetting:initFuncItem(child, index)
    local icon = child:getChildByName("icon");
    local text =  child:getChildByName("text");
    local bubble = child:getChildByName("bubble");
    local panel  = child:getChildByName("panel");

    local iconName = GameFuncSettingM.query(index, "icon");
    icon:loadTexture(getSettingIconPath("func", iconName));

    if self.funcSetting[index] == 1 then
        bubble:loadTexture(getSettingIconPath("system", "open"));
        TextStyleM.setTextStyle(text, TextStyleM.TEXT_SIZE_SMALL2, TextStyleM.TEXT_COLOR_DARK_BROWN);
    else
        bubble:loadTexture(getSettingIconPath("system", "close"));
        TextStyleM.setTextStyle(text, TextStyleM.TEXT_SIZE_SMALL2, TextStyleM.TEXT_COLOR_DARK_RED);
    end

    text:setString(GameFuncSettingM.query(index, "title"));

    local function onClick(sender, eventType)
        -- 点击时的回调
        if eventType == ccui.TouchEventType.ended then
            AudioM.playFx("button_click");
            if self.funcSet[index] == 1 then
                self.funcSet[index] = 0;
                bubble:loadTexture(getSettingIconPath("system", "close"));
                TextStyleM.setTextStyle(text, TextStyleM.TEXT_SIZE_SMALL2, TextStyleM.TEXT_COLOR_DARK_RED);
            else
                self.funcSet[index] = 1;
                bubble:loadTexture(getSettingIconPath("system", "open"));
                TextStyleM.setTextStyle(text, TextStyleM.TEXT_SIZE_SMALL2, TextStyleM.TEXT_COLOR_DARK_BROWN);
            end
        end
    end
    bubble:addTouchEventListener(onClick);

    local function onPanelClick(sender, eventType)
        if eventType == ccui.TouchEventType.ended then
            confirm2(CONFIRM_TYPE_OK, GameFuncSettingM.query(index, "title"), GameFuncSettingM.query(index, "detail"));
        end
    end

    panel:addTouchEventListener(onPanelClick);
end

-- 获取游戏评分的地址
function UISystemSetting:getFeedbackUrl()
    if PUBLISH_PLATFORM == PUBLISH_TYPE_GOOGLE_PLAY then
        return getLocStr("feedback_google_url");
    elseif PUBLISH_PLATFORM == PUBLISH_TYPE_AMAZON then
        return getLocStr("feedback_amazon_url");
    elseif PUBLISH_PLATFORM == PUBLISH_TYPE_APP_STORE then
        return getLocStr("feedback_ios_url");
    else
        return "";
    end
end

-- 注册项目点击回调
function UISystemSetting:registerItemTouchEvent(node)
    local btnOk = findChildByName(self.node, "BT/btn_ok");

    if self.type == SYSTEM then
        -- 系统设置
        local bg = node:getChildByName("bg");
        local function onClick(sender, eventType)
            if eventType == ccui.TouchEventType.began then
                bg:setScale(0.9);
            elseif eventType == ccui.TouchEventType.canceled then
                bg:setScale(1.0);
            elseif eventType == ccui.TouchEventType.ended then
                AudioM.playFx("button_click");
                bg:setScale(1.0);

                if node.index == "language" and ALLOW_TO_SWITCH_LANG ~= 1 and getLang() == "zh" then
                    -- 不可切换语言/非简体中文版本允许切换
                    alert(getLocStr("function_is_not_open"));
                    return;

                elseif node.index == "feedBack" then
                    -- GOOGLE评分，打开链接
                    local url = self:getFeedbackUrl();
                    cc.Application:getInstance():openURL(url);
                    UIMgr.getCurrentScene():removeFormByName("UISystemSetting");
                    return;

                elseif node.index == "email" then
                    -- 客服邮箱
                    local name = ME.user.dbase:query("name") or "";
                    local title = "From " .. name;

                    sendMailTo(getLocStr("custom_service_email"), title, "");
                    return;

                elseif node.index == "facebook" then
                    -- FACEBOOK， 打开链接
                    local url = getLocStr("facebook_url");
                    cc.Application:getInstance():openURL(url);
                    EventMgr.fire(event.CLICK_FACEBOOK);
                    UIMgr.getCurrentScene():removeFormByName("UISystemSetting");
                    return;

                elseif node.index == "error" then
                    -- 错误日志
                    UIMgr.getCurrentScene():removeFormByName("UIErrorInfo");
                    local uiError = UIErrorInfo.create();
                    UIMgr.getCurrentScene():addForm(uiError);
                    return;

                elseif node.index == "clear" then
                    if DEBUG_MODE == 1 then
                        UIMgr.clearUnusedTextures();
                    end
                    return;

                elseif node.index == "sdk_achievement" then
                    if PUBLISH_PLATFORM == PUBLISH_TYPE_GOOGLE_PLAY then
                        if not get3rdAccountLoginInfo(CHANNEL_GOOGLE) then
                            self.needShowSdkAchievements = true;
                            showGoogleLogin();
                            return;
                        end

                        -- 显示Google成就
                        GoogleAchievementM.displayGoogleAchievements();
                    elseif PUBLISH_PLATFORM == PUBLISH_TYPE_AMAZON then
                        if not get3rdAccountLoginInfo(CHANNEL_AMAZON) then
                            self.needShowSdkAchievements = true;
                            showAmazonLogin();
                            return;
                        end

                        -- 显示亚马逊成就
                        AmazonAchievementM.displayAmazonAchievements();
                    elseif PUBLISH_PLATFORM == PUBLISH_TYPE_APP_STORE or PUBLISH_PLATFORM == PUBLISH_TYPE_APP_STORE_CN then
                        if not get3rdAccountLoginInfo(CHANNEL_GAME_CENTER) then
                            self.needShowSdkAchievements = true;
                            showGameCenterLogin();
                            return;
                        end

                        -- 显示GameCenter成就
                        GameCenterAchievementM.showAchievements();
                    end
                    return;

                elseif node.index == "sdk_leaderboard" then
                    if PUBLISH_PLATFORM == PUBLISH_TYPE_GOOGLE_PLAY then
                        if not get3rdAccountLoginInfo(CHANNEL_GOOGLE) then
                            self.needShowSdkLeaderboard = true;
                            showGoogleLogin();
                            return;
                        end

                        -- 显示Google排行榜
                        GoogleLeaderboardM.displayAllGoogleLeaderboards();
                    elseif PUBLISH_PLATFORM == PUBLISH_TYPE_AMAZON then
                        if not get3rdAccountLoginInfo(CHANNEL_AMAZON) then
                            self.needShowSdkLeaderboard = true;
                            showAmazonLogin();
                            return;
                        end

                        -- 显示亚马逊排行榜
                        AmazonLeaderboardM.displayAllAmazonLeaderboards();
                    elseif PUBLISH_PLATFORM == PUBLISH_TYPE_APP_STORE or PUBLISH_PLATFORM == PUBLISH_TYPE_APP_STORE_CN then
                        if not get3rdAccountLoginInfo(CHANNEL_GAME_CENTER) then
                            self.needShowSdkLeaderboard = true;
                            showGameCenterLogin();
                            return;
                        end

                        -- 显示GameCenter排行榜
                        GameCenterLeaderboardM.showLeaderBoards();
                    end
                    return;

                elseif node.index == "account" then
                    -- 账号绑定/账号切换
                    UIMgr.getCurrentScene():removeFormByName("UIAccountBind");
                    local uiAccountBind = UIAccountBind.create();
                    UIMgr.getCurrentScene():addForm(uiAccountBind);
                    return;

                elseif node.index == "help" then
                    -- 内置客服
                    showFAQs();
                    return;

                elseif node.index == "account_center" then
                    -- 个人中心
                    showAccountCenter();
                    return;

                elseif node.index == "forum" then
                    -- 论坛，打开链接
                    local url = getLocStr("forum_url");

                    if PUBLISH_PLATFORM == PUBLISH_TYPE_LT then
                        url = getLocStr("forum_url_lt");
                    end
                    cc.Application:getInstance():openURL(url);
                    EventMgr.fire(event.CLICK_FORUM);
                    UIMgr.getCurrentScene():removeFormByName("UISystemSetting");
                    return;

                elseif node.index == "lobi" then
                    -- 日语版本使用lobi，打开链接
                    if isAndroidPlatform() or isIosPlatform() then
                        openLobiOfficialCommunity();
                    else
                        local url = getLocStr("lobi_url");
                        cc.Application:getInstance():openURL(url);
                    end

                    EventMgr.fire(event.CLICK_FORUM);
                    UIMgr.getCurrentScene():removeFormByName("UISystemSetting");
                    return;

                elseif node.index == "share" then
                    -- 分享
                    if isShareFuncOpen() then
                        -- 显示游戏分享
                        local title = getLocStr("system_share_title");
                        local desc = getLocStr("system_share_desc");

                        showShareForm(SHARE_TYPE_GAME, title, desc);
                    else
                        alert(getLocStr("function_is_not_open"));
                    end
                    return;

                elseif node.index == "weibo"
                    or node.index == "weixin" then
                    -- 功能暂未开放
                    alert(getLocStr("function_is_not_open"));
                    return;

                elseif node.index == "card_bonus" then
                    if DungeonAreaM.isDungeonPassed(ME.user, 11) == false then
                        -- 尚未通关第一小关，暂不启用密令功能
                        alert(string.format(getLocStr("slime_food_open"), "  " .. DungeonAreaM.query(11, "name") .. "  "));
                        return;
                    end

                    -- 兑换码/密令
                    require "game/ui/form/setting/UICardBonus";
                    UIMgr.getCurrentScene():removeFormByName("UICardBonus");
                    local uiCardBonus = UICardBonus.create();
                    UIMgr.getCurrentScene():addForm(uiCardBonus);

                    return;
                elseif node.index == "phone_record" then
                    -- 检查能否领取绑定奖励（雷霆平台已经绑定了，奖励还没有领取）
                    if PUBLISH_PLATFORM == PUBLISH_TYPE_LT and LeiTingAgent then
                        -- 已经绑定什么也不做
                        if BuffDataM.query("id_card_record", 1) ~= 1 then
                            local function callback(phone)
                                if phone == nil then
                                    -- 未绑定
                                    -- 打开手机号记录页面
                                    require "game/ui/form/setting/UIPhoneNumberRecord"
                                    UIMgr.getCurrentScene():removeFormByName("UIPhoneNumberRecord");

                                    local uiPhoneBind = UIPhoneNumberRecord.create();
                                    UIMgr.getCurrentScene():addForm(uiPhoneBind);
                                else
                                    -- 已绑定，phone就是手机号
                                    Operation.cmd_record_phone_number(phone, PhoneNumberRecordM.OPERATE_RECORD_LT_PHONE_NUMBER);
                                end
                            end

                            -- 请求获取绑定手机号
                            LeiTingAgent.getBindedPhone(callback);
                        end

                        return;
                    end

                    -- 打开手机号记录页面
                    require "game/ui/form/setting/UIPhoneNumberRecord"
                    UIMgr.getCurrentScene():removeFormByName("UIPhoneNumberRecord");

                    local uiPhoneBind = UIPhoneNumberRecord.create();
                    UIMgr.getCurrentScene():addForm(uiPhoneBind);

                    return;

                elseif node.index == "id_card_record" then
                    -- 打开身份记录页面
                    require "game/ui/form/setting/UIIdcardRecord"
                    UIMgr.getCurrentScene():removeFormByName("UIIdcardRecord");

                    local uiForm = UIIdcardRecord.create();
                    UIMgr.getCurrentScene():addForm(uiForm);

                    return;

                elseif node.index == "lt_operation" then
                    -- 雷霆运营
                    local url = MaintainBulletinM.getLtOperationUrl();
                    if not url or url == "" then
                        return;
                    end

                    UserDefaultM.setStringForKey("click_lt_operation", 1);
                    self:checkTip(node);

                    cc.Application:getInstance():openURL(url);

                    return;
                end

                -- 任然使用本界面的项目，更换标记
                self.type = systemTypeFlag[node.index];

                -- 重绘页面
                self:redraw();

                -- 弹出效果
                playAppearEffect(self);
            end
        end
        bg:addTouchEventListener(onClick);
    elseif self.type == LANGUAGE then
        -- 语言
        local bg = node:getChildByName("bg");
        local focus = node:getChildByName("focus");

        local function onClick(sender, eventType)
            if eventType == ccui.TouchEventType.ended then
                AudioM.playFx("button_click");
                local lastFocus = self.focus:getChildByName("focus");
                lastFocus:setVisible(false);
                focus:setVisible(true);
                self.focus = node;

                -- 选择语言为当前语言，确认按钮需要置灰
                -- 不允许切换语言时，选择非简体中文，确认按钮也要置灰
                local selectLang = node.index;
                if selectLang == getLang()
                   or ALLOW_TO_SWITCH_LANG ~= 1 and selectLang ~= "zh" then
                    btnOk:setTouchEnabled(false);
                    btnOk:setBright(false);
                else
                    btnOk:setTouchEnabled(true);
                    btnOk:setBright(true);
                end
            end
        end
        bg:addTouchEventListener(onClick);
    elseif self.type == DEBUG then
        -- DEBUG
        local bg = node:getChildByName("bg");

        local function onClick(sender, eventType)
            if eventType == ccui.TouchEventType.began then
                bg:setScale(0.9);
            elseif eventType == ccui.TouchEventType.canceled then
                bg:setScale(1.0);
            elseif eventType == ccui.TouchEventType.ended then
                bg:setScale(1.0);
                AudioM.playFx("button_click");
                if node.index == "gd" then
                    -- GD功能
                    UIMgr.getCurrentScene():removeFormByName("UIGD");
                    local uiGd = UIGD.create();
                    UIMgr.getCurrentScene():addForm(uiGd);
                elseif node.index == "error" then
                    -- 错误日志
                    UIMgr.getCurrentScene():removeFormByName("UIErrorInfo");
                    local uiError = UIErrorInfo.create();
                    UIMgr.getCurrentScene():addForm(uiError);
                elseif node.index == "clear" then
                    if DEBUG_MODE == 1 then
                        UIMgr.clearUnusedTextures();
                    end
                end
            end
        end
        bg:addTouchEventListener(onClick);
    end

end

-- 标签页
function UISystemSetting:redrawTabs()
    local tabNode = findChildByName(self.node, "CT/tabs");

    -- 标签页数量
    local tabNum = TAB_NUM;

    -- 置灰颜色
    local blendColor = TextStyleM.TEXT_COLOR_BLEND;
    local normalColor = TextStyleM.TEXT_COLOR_NORMAL;

    -- 标签
    self.tabList = {};

    for i = 1, tabNum do
        local child = tabNode:getChildByName("tab" .. i);
        child:setName("tab" .. i);
        child.index = i;

        self.tabList[i] = child;

        self:registerTabTouchEvent(child);

        local tabLight = findChildByName(child, "light");

        local tabText = findChildByName(child, "text");
        local tabIcon = findChildByName(child, "icon");

        local kerning = 0;
        if not isFullWidthLang() then
            kerning = -4;
        end
        TextStyleM.setOutlineStyle(tabText, TextStyleM.TEXT_OUTLINE_SIZE, TextStyleM.TEXT_OUTLINE_COLOR_DARK);
        TextStyleM.setTextStyle(tabText, TextStyleM.TEXT_SIZE_SMALL2, TextStyleM.TEXT_COLOR_BROWN_YELLOW, true, kerning);

        if i == 1 then
            -- 设置
            tabText:setString(getLocStr("setting_tab"));
        elseif i == 2 then
            -- 公告
            tabText:setString(getLocStr("notify_tab"));
        else
            -- DEBUG
            tabText:setString(getLocStr("btn_text_debug"));
        end

        -- DEBUG 模式下才开启DEBUG标签
        if i == 3 and DEBUG_MODE ~= 1 then
            child:setVisible(false);
        end

        local formType = self.type;
        if table.indexOf(firstType, self.type) == -1 then
            formType = SYSTEM;
        end

        if i ~= formType then
            tabText:setColor(blendColor);
            tabIcon:setColor(blendColor);
            tabLight:setVisible(false);
        else
            tabLight:setVisible(true);
            self.tabSelect = child;
        end
    end

    for i = 1, #self.tabList do
        local tab = self.tabList[i];
        tab:setPositionY(tab:getPositionY() + 100);
    end

    if table.indexOf(firstType, self.type) == -1 then
        tabNode:setVisible(false);
        return;
    end

    -- tab的动画效果
    performWithDelay(self, function() self:playTabEffect(); end, 0.2);
end

-- 页签动画效果
function UISystemSetting:playTabEffect()
    -- 带窗口动画播放结束后，页签从上面往下掉
    for i = 1, #self.tabList do
        local tab = self.tabList[i];
        local pos = cc.p(tab:getPosition());
        local delay = cc.DelayTime:create(0.2 * (i - 1));
        local moveDown = cc.MoveTo:create(0.2, cc.p(pos.x, pos.y - 100 - 5));
        local moveBack = cc.MoveTo:create(0.2, cc.p(pos.x, pos.y - 100));
        local action = cc.Sequence:create(delay, moveDown, moveBack);
        tab:runAction(action);
    end
end

-- 注册标签页点击回调
function UISystemSetting:registerTabTouchEvent(node)
    -- 节点
    local tabLight = node:getChildByName("light");
    local tabIcon = node:getChildByName("icon");
    local tabText = node:getChildByName("text");

    -- 置灰颜色
    local blendColor = TextStyleM.TEXT_COLOR_BLEND;
    local normalColor = TextStyleM.TEXT_COLOR_NORMAL;

    local function onClick(sender, eventType)
        -- 点击时的回调
        if eventType == ccui.TouchEventType.ended then
            AudioM.playFx("button_click");
            -- 去除上一个高亮
            self.tabSelect:getChildByName("text"):setColor(blendColor);
            self.tabSelect:getChildByName("icon"):setColor(blendColor);
            self.tabSelect:getChildByName("light"):setVisible(false);

            -- 设置本身高亮
            tabLight:setVisible(true);
            tabText:setColor(normalColor);
            tabIcon:setColor(normalColor);

            self.tabSelect = node;

            if node.index == 1 then
                self.type = SYSTEM;
            elseif node.index == 2 then
                self.type = NOTIFY;
            else
                self.type = DEBUG;
            end

            -- 重绘页面
            self:redraw();
        end
    end

    tabIcon:addTouchEventListener(onClick);
end

-- 注册点击事件
function UISystemSetting:registerTouchEvent()
    -- 注册确定按钮点击事件
    local btnOk = findChildByName(self.node, "BT/btn_ok");
    local function onOkClick(sender, eventType)
        if eventType == ccui.TouchEventType.ended then
            if self.type == LANGUAGE then
                -- 语言设置
                local function okFunc()
                    local function delayCall()
                        local targetLang = "en";
                        local function onSwitchLang(success, errcode)
                            if success ~= true then
                                local errCodeStr = string.format(getLocStr("download_pkg_fail"), errcode);
                                alert(errCodeStr);

                                if IGNORE_DOWNLOAD_PKG_RESULT ~= 1 then
                                    return;
                                end
                            end

                            -- 飘字提示
                            alert(getLocStr("change_language_tips2"));

                            setLang(targetLang);
                            initLang();

                            local function callback()
                                if isAndroidPlatform() then
                                    restartApp();
                                else
                                    exitApp();
                                end
                            end
                            -- 延迟执行
                            performWithDelay(self.node, callback, 1);
                        end

                        local needPkg = "";
                        -- 设置切换语言
                        targetLang = self.focus.index;
                        -- 判断需要下载安装包的语言
                        local needPkgArr = LanguageM.getNeedPkg();
                        if needPkgArr[targetLang] then
                            needPkg = needPkgArr[targetLang];
                        end

                        if needPkg ~= "" then
                            downloadPkg(getLocStr("download_pkg_title"), getLocStr("download_pkg_desc"), needPkg, onSwitchLang);
                        else
                            onSwitchLang(true);
                        end
                    end
                    -- 延迟重登
                    performWithDelay(self.node, delayCall, 0.01);
                end

                confirm2(CONFIRM_TYPE_OK_CANCEL, getLocStr("slime_note"), getLocStr("change_language_tips"),
                    okFunc, nil, getLocStr("btn_text_ok"), getLocStr("btn_text_cancel"),
                     { ["cancelColor"] = "blue"} );
            else
                -- 换到系统设置界面
                self.type = SYSTEM;
                self:redraw();
            end
        end
    end
    AddBackEventHandler(self, btnOk, onOkClick);
    TextStyleM.setTextStyle(btnOk, TextStyleM.TEXT_SIZE_MIDDLE, TextStyleM.TEXT_COLOR_BROWN_YELLOW, true);
    btnOk:setTitleText(getLocStr("btn_text_select"));

   -- 注册返回按钮点击事件
    local btnBack = findChildByName(self.node, "BT/btn_back");
    local function onBackClick(sender, eventType)
        if eventType == ccui.TouchEventType.ended then
            AudioM.playFx("button_return");
            if self.type == SYSTEM or self.type == NOTIFY or self.type == DEBUG then
                -- 关闭当前界面
                UIMgr.getCurrentScene():removeFormByName("UISystemSetting");
            else
                -- 检查推送是否需要更改
                if self.type == PUSH and PushM.ifChangeSetting(self.pushSet) then
                    Operation.cmd_update_push_setting(self.pushSet);
                elseif self.type == FUNC and GameFuncSettingM.isSettingChanged(self.funcSet) then
                    Operation.cmd_update_game_func_setting(self.funcSet);
                end

                -- 换到系统设置界面
                self.type = SYSTEM;
                self:redraw();

                -- 弹出效果
                playAppearEffect(self);
            end
        end
    end
    AddBackEventHandler(self, btnBack, onBackClick);
    TextStyleM.setTextStyle(btnBack, TextStyleM.TEXT_SIZE_MIDDLE, TextStyleM.TEXT_COLOR_BROWN_YELLOW, true);
    btnBack:setTitleText(getLocStr("btn_text_back"));
end

-- 注册事件处理回调函数
function UISystemSetting:registerEventCallback()
    -- 关注G+账号登录成功的事件
    EventMgr.register("UISystemSetting", event.GOOGLE_CONNECTED, function()
        if self.needShowSdkAchievements then
            -- 显示Google成就
            GoogleAchievementM.displayGoogleAchievements();
            self.needShowSdkAchievements = false;
        elseif self.needShowSdkLeaderboard then
            -- 显示Google排行榜
            GoogleLeaderboardM.displayAllGoogleLeaderboards();
            self.needShowSdkLeaderboard = false;
        end
    end);

    -- 关注第三方账号登录成功的事件
    EventMgr.register("UISystemSetting", event.THIRD_ACCOUNT_LOGINED, function(para)
        local channel = para.channel;
        if channel == CHANNEL_AMAZON then
            if para.agsReady ~= "1" then
                -- GameCircle尚未准备完毕
                return;
            end

            if self.needShowSdkAchievements then
                -- 显示亚马逊成就
                AmazonAchievementM.displayAmazonAchievements();
                self.needShowSdkAchievements = false;
            elseif self.needShowSdkLeaderboard then
                -- 显示亚马逊排行榜
                AmazonLeaderboardM.displayAllAmazonLeaderboards();
                self.needShowSdkLeaderboard = false;
            end
        end
    end);

    -- 关注亚马逊GameCircle准备完毕的事件
    EventMgr.register("UISystemSetting", event.GAME_CIRCLE_READY, function()
        if self.needShowSdkAchievements then
            -- 显示亚马逊成就
            AmazonAchievementM.displayAmazonAchievements();
            self.needShowSdkAchievements = false;
        elseif self.needShowSdkLeaderboard then
            -- 显示亚马逊排行榜
            AmazonLeaderboardM.displayAllAmazonLeaderboards();
            self.needShowSdkLeaderboard = false;
        end
    end);

    -- 关注GameCenter账号登录的事件
    EventMgr.register("UISystemSetting", event.GAME_CENTER_CONNECTED, function(para)
        if self.needShowSdkAchievements then
            -- 显示GameCenter成就
            GameCenterAchievementM.showAchievements();
            self.needShowSdkAchievements = false;
        elseif self.needShowSdkLeaderboard then
            -- 显示GameCenter排行榜
            GameCenterLeaderboardM.showLeaderBoards();
            self.needShowSdkLeaderboard = false;
        end
    end);

    -- 手机号记录奖励
    EventMgr.register("UISystemSetting", event.PHONE_ID_BIND_RESULT, function(args)
        if args.result == PHONE_NUMBER_RECORD_OK then
            if args.recordType == PhoneNumberRecordM.OPERATE_RECORD_LT_PHONE_NUMBER
                or args.recordType == PhoneNumberRecordM.OPERATE_RECORD_PHONE_NUMBER then
                -- 显示奖励
                local bonuslist = FormulaM.invoke("CALC_RECORD_PHONE_NUMBER_BONUS");
                showBonusNotifyForm(getLocStr("phone_number_submited"), {{2, "gem", 10}});
                UIMgr:getCurrentScene():removeFormByName("UIPhoneNumberRecord");
            elseif args.recordType == PhoneNumberRecordM.OPERATE_RECORD_ID_CARD then
                UIMgr:getCurrentScene():removeFormByName("UIIdcardRecord");
                alert(getLocStr("id_card_submited"));
            end

            -- 整理当前可以显示的设置项目
            self:arrangeSystemItems();
            self:redraw();
        end

    end);

    -- 界面析构后，需要清理下
    self:registerScriptHandler(function(ev)
        if ev == "exit" then
            cclog("UISystemSetting 界面析构清理");
            EventMgr.removeAll("UISystemSetting");
        elseif ev == "enter" then
            -- 公告更新事件
            EventMgr.register("UISystemSetting", event.BOARDS_UPDATE, function()
                if self.type == NOTIFY then
                    -- 在公告界面，需要重绘
                    self:redraw();
                end
            end);

            -- 获得焦点
            EventMgr.register("UISystemSetting", event.FOCUS_CHANGED, function(para)
                if para["get"] == "UISystemSetting" then
                    -- TODO
                end
            end);

            if UIMgr.getCurrentScene().mainMap then
                UIMgr.getCurrentScene().mainMap:stopEffect();
            end

            local uiForm = UIMgr.getCurrentScene():getFormByName("UINewWorkshop");
            if uiForm then
                uiForm:hideBottomMenu();
            end

            local uiTalentMain = UIMgr.getCurrentScene():getFormByName("UITalentMain");
            if uiTalentMain then
                uiTalentMain:hideButtons();

                -- 隐藏冈布奥模型
                uiTalentMain:setSlimeVisible(false);
            end
        end
    end);
end

-- 界面播放弹出效果
function UISystemSetting:playFormEffect()
    -- 弹出效果
    playAppearEffect(self);
end

-- 适配
function resize(node)
    -- bg居中显示并充满整个屏幕
    AlignM.fitToScreen(node, "bg");

    -- CT居中并缩放至合适大小
    AlignM.alignToCenter(node, "CT");

    -- BT置于底部并缩放至合适大小
    AlignM.alignToBottomCenter(node, "BT");
end
